#include "setupdialog.h"
#include "ui_setupdialog.h"
#include "ruleitemdelegate.h"
#include "ruleitemmodel.h"

#include <QMessageBox>
#include <QSettings>
#include <QColorDialog>
#include <QFontDialog>
#include <QFileDialog>
#include <QFile>
#include <QPalette>
#include <QPrintDialog>
#include <QPrinter>
#include <QPainter>
#include <QStandardPaths>

#define MINICELLS 16

SetupDialog::SetupDialog(QWidget *parent) :
    QDialog(parent),
    model(new RuleItemModel(this)),
    delegate(new RuleItemDelegate(this)),
    ui(new Ui::SetupDialog)
{
    ui->setupUi(this);

    connect(ui->insertRuleButton, SIGNAL(clicked()), this, SLOT(onInsertRule()));
    connect(ui->removeRuleButton, SIGNAL(clicked()), this, SLOT(onRemoveRule()));
    connect(ui->applyButton, SIGNAL(clicked()), this, SLOT(onApply()));
    connect(ui->okButton, SIGNAL(clicked()), this, SLOT(onOk()));
    connect(ui->headerIconButton, SIGNAL(clicked()), this, SLOT(onHeaderIcon()));
    connect(ui->headerFontButton, SIGNAL(clicked()), this, SLOT(onHeaderFont()));
    connect(ui->headerColorButton, SIGNAL(clicked()), this, SLOT(onHeaderColor()));
    connect(ui->footerIconButton, SIGNAL(clicked()), this, SLOT(onFooterIcon()));
    connect(ui->footerFontButton, SIGNAL(clicked()), this, SLOT(onFooterFont()));
    connect(ui->FooterColorButton, SIGNAL(clicked()), this, SLOT(onFooterColor()));
    connect(ui->testButton, SIGNAL(clicked()), this, SLOT(onPrintTest()));
    connect(ui->selectLogDirButton, SIGNAL(clicked()), this, SLOT(onSelectDir()));

    ui->tableView->setModel(model);
    ui->tableView->setItemDelegate(delegate);
    ui->tableView->horizontalHeader()->setSectionResizeMode(RuleItemModel::Printer, QHeaderView::Stretch);

    readConfig();
    initUi();
}

SetupDialog::~SetupDialog()
{
    delete ui;
}

void SetupDialog::getConfigData(QList<PrintRule *> &rules, GeneralSettings &gsettings, PrintFormat &pformat, FilmPaperMap &fpmap)
{
    model->getRuleList(rules);
    gsettings = general;
    pformat = format;
    fpmap = paperMap;
}

void SetupDialog::getConfigDataFromFile(QList<PrintRule*> &rules, GeneralSettings &gsettings, PrintFormat &pformat, FilmPaperMap &fpmap)
{
    RuleItemModel::getRulesFromFile(rules);
    getSettingsFromFile(gsettings, pformat, fpmap);
}

void SetupDialog::initUi()
{
    ui->portSpin->setValue(general.port);
    ui->aetCombo->setCurrentText(general.defaultAE);
    ui->loglevelCombo->setCurrentIndex(general.log);
    ui->autoRunCheck->setChecked(general.autoRun);
    ui->sysTrayCheck->setChecked(general.miniToTray);
    ui->saveLogCheck->setChecked(general.saveLog);
    ui->logDirEdit->setText(general.logDir);

    ui->headerEdit->setFont(format.header.font);
    QPalette palette = ui->headerEdit->palette();
    palette.setColor(QPalette::Text, format.header.color);
    ui->headerEdit->setPalette(palette);
    ui->headerEdit->setText(format.header.text);
    ui->headerAlignCombo->setCurrentIndex(format.header.align);
    if (!format.header.icon.isNull()) {
        int height = ui->headerEdit->fontMetrics().height();
        ui->headerIconLabel->setPixmap(format.header.icon.scaledToHeight(height));
    }

    ui->footerEdit->setFont(format.footer.font);
    palette = ui->footerEdit->palette();
    palette.setColor(QPalette::Text, format.footer.color);
    ui->footerEdit->setPalette(palette);
    ui->footerEdit->setText(format.footer.text);
    ui->footerAlignCombo->setCurrentIndex(format.footer.align);
    if (!format.footer.icon.isNull()) {
        int height = ui->footerEdit->fontMetrics().height();
        ui->footerIconLabel->setPixmap(format.footer.icon.scaledToHeight(height));
    }

    ui->xSpacingSpin->setValue(format.xSpacing);
    ui->ySpacingSpin->setValue(format.ySpacing);

    ui->film8X10Combo->setCurrentIndex(paperMap.film8x10);
    ui->film8_5X11Combo->setCurrentIndex(paperMap.film8_5x11);
    ui->film10X12Combo->setCurrentIndex(paperMap.film10x12);
    ui->film10X14Combo->setCurrentIndex(paperMap.film10x14);
    ui->film11X14Combo->setCurrentIndex(paperMap.film11x14);
    ui->film14X14Combo->setCurrentIndex(paperMap.film14x14);
    ui->film14X17Combo->setCurrentIndex(paperMap.film14x17);
    ui->filmDefaultCombo->setCurrentIndex(paperMap.filmDefault);
}

void SetupDialog::setAutoRun(bool yes)
{
    QString startupDir = QStandardPaths::locate(QStandardPaths::ApplicationsLocation,
                                            "Startup",
                                            QStandardPaths::LocateDirectory);
    if (!startupDir.isEmpty()) {
        QString shortcut = QString("%1/%2.lnk").arg(startupDir, QApplication::applicationDisplayName());
        if (yes) {
            QFile::link(QApplication::applicationFilePath(), shortcut);
        } else {
            QFile::remove(shortcut);
        }
    }
}

void SetupDialog::onSelectDir()
{
    QString dir = QFileDialog::getExistingDirectory(this, tr("Select Log Folder"), general.logDir);
    if (!dir.isEmpty()) {
        ui->logDirEdit->setText(dir);
    }
}

void SetupDialog::onInsertRule()
{
    QModelIndex index = ui->tableView->currentIndex();
    if (index.isValid())
        model->insertRow(index.row()+1);
    else
        model->insertRow(model->rowCount(QModelIndex()));
}

void SetupDialog::onRemoveRule()
{
    QModelIndex index = ui->tableView->currentIndex();
    if (index.isValid()) {
        if (QMessageBox::Ok == QMessageBox::warning(this, tr("Remove Print Rule"),
                                                    tr("Are you sure to remove this print rule?"),
                                                    QMessageBox::Ok|QMessageBox::Cancel))
            model->removeRow(index.row());
    }
}

void SetupDialog::onApply()
{
    general.port = ui->portSpin->value();
    general.defaultAE = ui->aetCombo->currentText();
    general.log = (LogLevel)ui->loglevelCombo->currentIndex();
    if (general.autoRun != ui->autoRunCheck->isChecked()) {
        general.autoRun = ui->autoRunCheck->isChecked();
        setAutoRun(general.autoRun);
    }
    general.miniToTray = ui->sysTrayCheck->isChecked();
    general.saveLog = ui->saveLogCheck->isChecked();
    general.logDir = ui->logDirEdit->text();

    format.header.text = ui->headerEdit->text();
    format.header.align = (AlignType)ui->headerAlignCombo->currentIndex();
    format.footer.text = ui->footerEdit->text();
    format.footer.align = (AlignType)ui->footerAlignCombo->currentIndex();
    format.xSpacing = ui->xSpacingSpin->value();
    format.ySpacing = ui->ySpacingSpin->value();

    paperMap.definedWidth = ui->definedWidthSpin->value();
    paperMap.definedHeight = ui->definedHeightSpin->value();
    paperMap.film8x10 = (PaperSize)ui->film8X10Combo->currentIndex();
    paperMap.film8_5x11 = (PaperSize)ui->film8_5X11Combo->currentIndex();
    paperMap.film10x12 = (PaperSize)ui->film10X12Combo->currentIndex();
    paperMap.film10x14 = (PaperSize)ui->film10X14Combo->currentIndex();
    paperMap.film11x14 = (PaperSize)ui->film11X14Combo->currentIndex();
    paperMap.film14x14 = (PaperSize)ui->film14X14Combo->currentIndex();
    paperMap.film14x17 = (PaperSize)ui->film14X17Combo->currentIndex();
    paperMap.filmDefault = (PaperSize)ui->filmDefaultCombo->currentIndex();

    saveConfig();
}

void SetupDialog::onHeaderColor()
{
    QColor color = QColorDialog::getColor(format.header.color, this);
    if (color.isValid()) {
        format.header.color = color;
        QPalette palette = ui->headerEdit->palette();
        palette.setColor(QPalette::Text, color);
        ui->headerEdit->setPalette(palette);
    }
}

void SetupDialog::onHeaderFont()
{
    format.header.font = QFontDialog::getFont(0, format.header.font, this);
    ui->headerEdit->setFont(format.header.font);
    if (!format.header.icon.isNull())
        ui->headerIconLabel->setPixmap(format.header.icon.scaledToHeight(
                                           ui->headerEdit->fontMetrics().height()));
}

void SetupDialog::onHeaderIcon()
{
    QSettings settings;
    QString file = settings.value(OPEN_FILE_PATH, ".").toString();
    file = QFileDialog::getOpenFileName(this, tr("Select Header Icon File"), file,
                                        tr("Icon (*.ico);;Bitmap (*.bmp);;JPEG (*.jpg);;PNG (*.png);;TIFF (*.tif);;All Files (*.*)"));
    if (!file.isEmpty()) {
        QPixmap pixmap(file);
        if (!pixmap.isNull()) {
            format.header.icon = pixmap;
            settings.setValue(OPEN_FILE_PATH, file);
            ui->headerIconLabel->setPixmap(pixmap.scaledToHeight(
                                               ui->headerEdit->fontMetrics().height()));
        }
    }
}

void SetupDialog::onFooterColor()
{
    QColor color = QColorDialog::getColor(format.footer.color, this);
    if (color.isValid()) {
        format.footer.color = color;
        QPalette palette = ui->footerEdit->palette();
        palette.setColor(QPalette::Text, color);
        ui->footerEdit->setPalette(palette);
    }
}

void SetupDialog::onFooterFont()
{
    format.footer.font = QFontDialog::getFont(0, format.footer.font, this);
    ui->footerEdit->setFont(format.footer.font);
    if (!format.footer.icon.isNull())
        ui->footerIconLabel->setPixmap(format.footer.icon.scaledToHeight(
                                           ui->footerEdit->fontMetrics().height()));
}

void SetupDialog::onFooterIcon()
{
    QSettings settings;
    QString file = settings.value(OPEN_FILE_PATH, ".").toString();
    file = QFileDialog::getOpenFileName(this, tr("Select Footer Icon File"), file,
                                        tr("Icon (*.ico);;Bitmap (*.bmp);;JPEG (*.jpg);;PNG (*.png);;TIFF (*.tif);;All Files (*.*)"));
    if (!file.isEmpty()) {
        QPixmap pixmap(file);
        if (!pixmap.isNull()) {
            format.footer.icon = pixmap;
            settings.setValue(OPEN_FILE_PATH, file);
            ui->footerIconLabel->setPixmap(pixmap.scaledToHeight(ui->footerEdit->fontMetrics().height()));
        }
    }
}

void SetupDialog::onPrintTest()
{
    QPrinter printer(QPrinter::HighResolution);
    QPrintDialog dialog(&printer, this);
    if (QDialog::Accepted == dialog.exec()) {
        switch ((PrintTest)ui->testTypeCombo->currentIndex()) {
        case PT_All:
            testAll(&printer);
            break;
        case PT_Resolution:
            testResolution(&printer);
            break;
        case PT_Grayscale:
            testGrayscale(&printer);
            break;
        case PT_Distortion:
            testDistortion(&printer);
            break;
        }
    }
}

void SetupDialog::onOk()
{
    onApply();
    accept();
}

void SetupDialog::readConfig()
{
    QFile file(GENERAL_CFG);
    if (file.open(QIODevice::ReadOnly)) {
        QDataStream in(&file);
        in >> general >> format >> paperMap;
        file.close();
    }
}

void SetupDialog::getSettingsFromFile(GeneralSettings &gsettings, PrintFormat &pformat, FilmPaperMap &fpmap)
{
    QFile file(GENERAL_CFG);
    if (file.open(QIODevice::ReadOnly)) {
        QDataStream in(&file);
        in >> gsettings >> pformat >> fpmap;
        file.close();
    }
}

void SetupDialog::saveConfig()
{
    QFile file(GENERAL_CFG);
    if (file.open(QIODevice::WriteOnly)) {
        QDataStream out(&file);
        out << general << format << paperMap;
        file.close();
    }

    model->saveData();
}

void SetupDialog::testAll(QPrinter *printer)
{
    int dpi = printer->resolution();
    QPainter painter(printer);
    QRect viewRect = painter.viewport();

    int cellWidth;
    bool portrait;
    if (viewRect.width() < viewRect.height()) {
        cellWidth = viewRect.width() / 6;
        portrait = true;
    } else {
        cellWidth = viewRect.height() / 6;
        portrait = false;
    }

    if (portrait) {
        int height = (viewRect.height()-cellWidth*4)/2;
        int x = viewRect.left();
        int y = viewRect.top();
        for (int i = 0; i < 2; ++i) {
            if (i == 1) y = viewRect.bottom()-height;

            painter.setBackgroundMode(Qt::OpaqueMode);
            int cx = x;
            for (int y1 = y; y1 < y+height/2; y1 += painter.pen().width()*2)
                painter.drawLine(cx, y1, cx+cellWidth, y1);
            painter.drawText(cx, y+height/2-painter.fontMetrics().descent(), QString::number(dpi));
            for (int x1 = cx; x1 < cx+cellWidth; x1 += painter.pen().width()*2)
                painter.drawLine(x1, y+height/2, x1, y+height);
            painter.drawText(cx, y+height-painter.fontMetrics().descent(), QString::number(dpi));

            painter.setBackgroundMode(Qt::TransparentMode);
            cx += cellWidth;
            for (int x1 = cx; x1 < cx+cellWidth*4; x1 += cellWidth) {
                painter.drawRect(x1, y, cellWidth, height);
                painter.drawLine(x1, y+height/2, x1+cellWidth/2, y);
                painter.drawLine(x1+cellWidth/2, y, x1+cellWidth, y+height/2);
                painter.drawLine(x1+cellWidth, y+height/2, x1+cellWidth/2, y+height);
                painter.drawLine(x1+cellWidth/2, y+height, x1, y+height/2);
            }
            painter.drawLine(cx, y+height/2, cx+cellWidth*4, y+height/2);
            painter.drawLine(cx, y+height/2, cx+cellWidth*2, y);
            painter.drawLine(cx+cellWidth*2, y, cx+cellWidth*4, y+height/2);
            painter.drawLine(cx+cellWidth*4, y+height/2, cx+cellWidth*2, y+height);
            painter.drawLine(cx+cellWidth*2, y+height, cx, y+height/2);

            painter.setBackgroundMode(Qt::OpaqueMode);
            cx += cellWidth*4;
            for (int x1 = cx; x1 < cx+cellWidth; x1 += painter.pen().width()*2)
                painter.drawLine(x1, y, x1, y+height/2);
            painter.drawText(cx, y+height/2-painter.fontMetrics().descent(), QString::number(dpi));
            for (int y1 = y+height/2; y1 < y+height; y1 += painter.pen().width()*2)
                painter.drawLine(cx, y1, cx+cellWidth, y1);
            painter.drawText(cx, y+height-painter.fontMetrics().descent(), QString::number(dpi));
        }

        do {
            int grayStep = cellWidth*4/256;
            int y1 = viewRect.top() + height;
            int y2 = viewRect.bottom() - height;
            int x1 = viewRect.left();
            int x2 = viewRect.right() - cellWidth;
            for (int i = 0; i < 256; ++i) {
                painter.fillRect(QRect(x1, y1+grayStep*i, cellWidth, grayStep), QColor(i, i, i));
                painter.fillRect(QRect(x2, y2-grayStep*i, cellWidth, grayStep), QColor(i, i, i));
            }
        } while(0);

        x = viewRect.left() + cellWidth;
        y = viewRect.top() + height;
        int rgb = 255;
        painter.setBackgroundMode(Qt::OpaqueMode);
        for (int y1 = y; y1 < y+cellWidth*4; y1 += cellWidth) {
            for (int x1 = x; x1 < x+cellWidth*4; x1 += cellWidth) {
                painter.fillRect(QRect(x1, y1, cellWidth, cellWidth), QColor(rgb, rgb, rgb));
                painter.drawText(x1, y1+painter.fontMetrics().height(), QString::number(rgb));
                rgb -= 17;
            }
        }
    } else {
        int width = (viewRect.width()-cellWidth*4)/2;
        int x = viewRect.left();
        int y = viewRect.top();
        for (int i = 0; i < 2; ++i) {
            if (i == 1) x = viewRect.right() - width;

            painter.setBackgroundMode(Qt::OpaqueMode);
            int cy = y;
            for (int y1 = cy; y1 < cy+cellWidth; y1 += painter.pen().width()*2)
                painter.drawLine(x, y1, x+width/2, y1);
            painter.drawText(x, y+cellWidth-painter.fontMetrics().descent(), QString::number(dpi));
            for (int x1 = x+width/2; x1 < x+width; x1 += painter.pen().width()*2)
                painter.drawLine(x1, cy, x1, cy+cellWidth);
            painter.drawText(x+width/2, y+cellWidth-painter.fontMetrics().descent(), QString::number(dpi));

            painter.setBackgroundMode(Qt::TransparentMode);
            cy += cellWidth;
            for (int y1 = cy; y1 < cy+cellWidth*4; y1 += cellWidth) {
                painter.drawRect(x, y1, width, cellWidth);
                painter.drawLine(x+width/2, y1, x+width, y1+cellWidth/2);
                painter.drawLine(x+width, y1+cellWidth/2, x+width/2, y1+cellWidth);
                painter.drawLine(x+width/2, y1+cellWidth, x, y1+cellWidth/2);
                painter.drawLine(x, y1+cellWidth/2, x+width/2, y1);
            }
            painter.drawLine(x+width/2, cy, x+width/2, cy+cellWidth*4);
            painter.drawLine(x+width/2, cy, x+width, cy+cellWidth*2);
            painter.drawLine(x+width, cy+cellWidth*2, x+width/2, cy+cellWidth*4);
            painter.drawLine(x+width/2, cy+cellWidth*4, x, cy+cellWidth*2);
            painter.drawLine(x, cy+cellWidth*2, x+width/2, cy);

            cy += cellWidth*4;
            for (int x1 = x; x1 < x+width/2; x1 += painter.pen().width()*2)
                painter.drawLine(x1, cy, x1, cy+cellWidth);
            painter.drawText(x, cy+cellWidth-painter.fontMetrics().descent(), QString::number(dpi));
            for (int y1 = cy; y1 < cy+cellWidth; y1 += painter.pen().width()*2)
                painter.drawLine(x+width/2, y1, x+width, y1);
            painter.drawText(x+width/2, cy+cellWidth-painter.fontMetrics().descent(), QString::number(dpi));
        }

        do {
            int grayStep = cellWidth*4/256;
            int y1 = viewRect.top();
            int y2 = viewRect.bottom() - cellWidth;
            int x1 = viewRect.left() + width;
            int x2 = viewRect.right() - width;
            for (int i = 0; i < 256; ++i) {
                painter.fillRect(QRect(x1+grayStep*i, y1, grayStep, cellWidth), QColor(i, i, i));
                painter.fillRect(QRect(x2-grayStep*i, y2, grayStep, cellWidth), QColor(i, i, i));
            }
        } while(0);

        x = viewRect.left() + width;
        y = viewRect.top() + cellWidth;
        int rgb = 255;
        painter.setBackgroundMode(Qt::OpaqueMode);
        for (int y1 = y; y1 < y+cellWidth*4; y1 += cellWidth) {
            for (int x1 = x; x1 < x+cellWidth*4; x1 += cellWidth) {
                painter.fillRect(QRect(x1, y1, cellWidth, cellWidth), QColor(rgb, rgb, rgb));
                painter.drawText(x1, y1+painter.fontMetrics().height(), QString::number(rgb));
                rgb -= 17;
            }
        }
    }
}

void SetupDialog::testResolution(QPrinter *printer)
{
    int dpi = printer->resolution();
    QPainter painter(printer);
    QRect viewRect = painter.viewport();

    int width = viewRect.width() / 6;
    int height = viewRect.height() / 6;

    painter.setBackgroundMode(Qt::OpaqueMode);
    painter.setBackground(QBrush(Qt::white));
    QPen pen1, pen2;
    pen1.setWidth(1);
    pen2.setWidth(2);

    int x, y;
    int x1, y1;
    for (int i = 0; i < 5; ++i) {
        switch (i) {
        case 0:
            x = viewRect.left();
            y = viewRect.top();
            break;
        case 1:
            x = viewRect.left() + width*4;
            y = viewRect.top();
            break;
        case 2:
            x = viewRect.left() + width*2;
            y = viewRect.top() + height*2;
            break;
        case 3:
            x = viewRect.left();
            y = viewRect.top() + height*4;
            break;
        case 4:
            x = viewRect.left() + width*4;
            y = viewRect.top() + height*4;
            break;
        }

        painter.setPen(pen1);
        for (y1 = y; y1 < y+height; y1 += painter.pen().width()*2)
            painter.drawLine(x, y1, x+width, y1);
        painter.drawText(x, y+height-painter.fontMetrics().descent(), QString::number(dpi));
        for (x1 = x; x1 < x+width; x1 += painter.pen().width()*2)
            painter.drawLine(x1, y+height, x1, y+height*2);
        painter.drawText(x, y+height*2-painter.fontMetrics().descent(), QString::number(dpi));
        painter.setPen(pen2);
        for (; x1 < x+width*2; x1 += painter.pen().width()*2)
            painter.drawLine(x1, y, x1, y+height);
        painter.drawText(x+width, y+height-painter.fontMetrics().descent(), QString::number(dpi/2));
        for (; y1 < y+height*2; y1 += painter.pen().width()*2)
            painter.drawLine(x1-width, y1, x1, y1);
        painter.drawText(x+width, y+height*2-painter.fontMetrics().descent(), QString::number(dpi/2));
    }
}

void SetupDialog::testGrayscale(QPrinter *printer)
{
    //int dpi = printer->resolution();
    QPainter painter(printer);
    QRect viewRect = painter.viewport();

    int cellWidth;
    if (viewRect.width() > viewRect.height()) {
        cellWidth = viewRect.height() / MINICELLS;
    } else {
        cellWidth = viewRect.width() / MINICELLS;
    }

    int rgb = 0;
    for (int y = viewRect.top(); y <= viewRect.bottom()-cellWidth; y += cellWidth) {
        for (int x = viewRect.left(); x <= viewRect.right()-cellWidth; x += cellWidth) {
            QRect rect(x, y, cellWidth, cellWidth);
            painter.drawRect(rect);
            painter.fillRect(rect, QColor(rgb, rgb, rgb));
            if (++rgb > 255) rgb = 0;
        }
    }

}

void SetupDialog::testDistortion(QPrinter *printer)
{
    //int dpi = printer->resolution();
    QPainter painter(printer);
    QRect viewRect = painter.viewport();

    int cellWidth;
    if (viewRect.width() > viewRect.height()) {
        cellWidth = viewRect.height() / MINICELLS;
    } else {
        cellWidth = viewRect.width() / MINICELLS;
    }

    // Vertical Lines
    for (int x = viewRect.left(); x < viewRect.right() + cellWidth; x += cellWidth)
        painter.drawLine(x, viewRect.top(), x, viewRect.bottom());
    // Horizontal Lines
    for (int y = viewRect.top(); y < viewRect.bottom() + cellWidth; y += cellWidth)
        painter.drawLine(viewRect.left(), y, viewRect.right(), y);

    for (int y = viewRect.top(); y < viewRect.bottom() + cellWidth*3; y += cellWidth*3) {
        for (int x = viewRect.left(); x < viewRect.right() + cellWidth*3; x += cellWidth*3) {
            painter.drawEllipse(QRect(x, y, cellWidth*2, cellWidth*2));
            painter.drawEllipse(QRect(x-cellWidth*2, y, cellWidth*3, cellWidth*2));
            painter.drawEllipse(QRect(x, y-cellWidth*2, cellWidth*2, cellWidth*3));
        }
    }
}
